package cn.itsource.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.json.JSONUtil;
import cn.itsource.bean.LoginInfo;
import cn.itsource.bean.User;
import cn.itsource.expection.BusinessException;
import cn.itsource.mapper.UserMapper;
import cn.itsource.service.IUserService;
import cn.itsource.util.JsonResult;
import cn.itsource.util.Md5Password;
import cn.itsource.util.MyUtils;
import cn.itsource.util.ValidateCodeUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static cn.itsource.util.RedisContants.*;

/**
 * @author : 张金铭
 * @description :
 * @create :2022-11-16 09:46:00
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 用户注册最后的校验
     * @param user
     * @return
     */
    @Override
    public JsonResult registered(User user) {
        //1.信息不能为空
        if (user==null){
            return JsonResult.error("信息不能为空");
        }
        //2.获取用户信息后验证两次密码
        String password = user.getPassword();
        String configPassword = user.getConfigPassword();
        String phone = user.getPhone();
        String code = user.getCode();
        //3.验证手机号
        if (!Validator.isMobile(phone)) {
            return JsonResult.error("手机号格式错误");
        }
        //3.1手机号查询用户表是否已被注册
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getPhone,phone);
        List<User> list = this.list(queryWrapper);
        //3.2已被注册
        if (list.size()!=0){
            return JsonResult.error("手机号已被注册");
        }
        //4.验证密码
        if (Strings.isBlank(configPassword)||Strings.isBlank(password)){
            return JsonResult.error("密码或二次密码不能为空格");
        }
        if(configPassword==null||password==null){
            return JsonResult.error("密码或二次密码不能为空");
        }
        if (!configPassword.equals(password)){
            return JsonResult.error("两次密码不一致");
        }
        //4.1拼接key
        String key = USER_PHONE_CODE+phone;
        //5.进入redis查询key
        String userCode = stringRedisTemplate.opsForValue().get(key);
        //6.验证
        if (!userCode.equals(code)){
            //错误
            return JsonResult.error("验证码错误");
        }
        //6.1正确，将用户存入用户表

        //6.2加密密码 获取盐值
        String salt = UUID.randomUUID().toString().toUpperCase();

        //6.3实用md5加密
        String md5Password = Md5Password.getMd5Password(password, salt);
        //存密码存盐
        user.setPassword(md5Password);
        user.setSalt(salt);

        //将用户信息插入用户表
        this.save(user);
        return JsonResult.success("注册成功");
    }


    /**
     * 发送验证码
     * @param phone
     * @return
     */

    @Override
    public JsonResult sendMobileCode(String phone) {
        //1.验证手机号的合法性
        if (!MyUtils.isValidPhoneNumber(phone)) {
            return JsonResult.error("手机号格式错误");
        }

        //2.手机号查询用户表是否已被注册
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getPhone,phone);
        List<User> list = this.list(queryWrapper);
        //2.1已被注册
        if (list.size()!=0){
            return JsonResult.error("手机号已被注册");
        }


        //3.没被注册
        //3.2设置改手机号今日发送验证码次数
//        String todayKey = User_PHONE_TODAY + phone;
//        stringRedisTemplate.opsForValue().set(todayKey,"1");
        //3.1发送验证码 6位数
        String code = ValidateCodeUtils.generateValidateCode4String(6);
        log.info(phone+"本次验证码为：{}",code);
        //将验证码存储到redis 5分钟
        stringRedisTemplate.opsForValue().set(USER_PHONE_CODE+phone,code,5, TimeUnit.MINUTES);
        //TODO 这里调用发送短信接口


        //返回
        return JsonResult.success("验证码发送成功");
    }


    /**
     * 验证手机号
     * @param phone
     * @return
     */
    @Override
    public JsonResult checkPhone(String phone) {
        if (!MyUtils.isValidPhoneNumber(phone)) {
            return JsonResult.error("手机号格式错误");
        }

        //2.手机号查询用户表是否已被注册
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getPhone,phone);
        List<User> list = this.list(queryWrapper);
        //2.1已被注册
        if (list.size()!=0){
            return JsonResult.error("手机号已被注册");
        }
        //2.2没被注册
        return JsonResult.success();
    }

    @Override
    public JsonResult login(User user) {
        //获取到雇员username,数据库查询对应的员工信息
        String username = user.getUsername();
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername,username);
        queryWrapper.or().eq(User::getEmail,username);
        queryWrapper.or().eq(User::getPhone,username);
        User userMgs = this.getOne(queryWrapper);
        //判断是否存在
        if (userMgs==null){
            throw new BusinessException("账号和密码不匹配");
        }
        //将传进来的密码加盐加密
        String md5Password = Md5Password.getMd5Password(user.getPassword(), userMgs.getSalt());
        //查询对应的员工信息后将前端传输的密码做比对
        String sqlPassword = userMgs.getPassword();
        if (!md5Password.equals(sqlPassword)){
            //若不相等，抛出异常
            throw new BusinessException("账号和密码不匹配2");
        }

        //若账号和密码都正确，则生成token令牌
        //生成一个token，作为登入令牌               true带下划线的UUID
        String token = cn.hutool.core.lang.UUID.randomUUID().toString(true);


        //将雇员对象转换为json存储
        LoginInfo loginInfo = BeanUtil.copyProperties(userMgs,LoginInfo.class);
        loginInfo.setId(userMgs.getId());
        String jsonEmp = JSONUtil.toJsonStr(loginInfo);
        String key = LOGIN_USER_KEY + token;

        //存储和设置有效期 360分钟
        stringRedisTemplate.opsForValue().set(key,jsonEmp,LOGIN_USER_TTL,TimeUnit.MINUTES);

        loginInfo.setToken(token);
        //返回
        return JsonResult.success(loginInfo);
    }
}
